package command

import (
	"pan/api"
	"pan/common/conf"
	"pan/common/log"
	"time"

	"github.com/jedib0t/go-pretty/v6/progress"
)

type DownloadCommand struct {
	docId    string
	savedDir string

	callback  *api.DownloadCallback
	pgWriter  progress.Writer
	pgTracker *progress.Tracker
}

func (d *DownloadCommand) Run(opts []*Option, args []string) {
	if !d.parseOption(opts) {
		return
	}

	if !conf.IsTokenValid() {
		panic("token is invalid, you must login first")
	}

	req := &api.DownloadRequest{
		Docid:    d.docId,
		UseHttps: true,
	}

	d.callback = &api.DownloadCallback{
		Start:    d.downloadStart,
		Progress: d.downloadProgress,
		Finish:   d.downloadFinish,
	}

	err := api.DownloadApi(d.savedDir, conf.GlobalToken.Tokenid, req, d.callback)
	if err != nil {
		panic(err)
	}
}

func (d *DownloadCommand) downloadStart(dir, filename string, total int64) {
	p := progress.NewWriter()
	p.SetAutoStop(true)
	p.SetTrackerLength(2)
	p.ShowETA(true)
	p.ShowOverallTracker(true)
	p.ShowTime(true)
	p.ShowTracker(true)
	p.ShowValue(true)
	p.SetMessageWidth(50)
	p.SetNumTrackersExpected(1)
	p.SetStyle(progress.StyleDefault)
	p.SetTrackerPosition(progress.PositionRight)
	p.SetUpdateFrequency(time.Millisecond * 100)
	p.Style().Colors = progress.StyleColorsExample
	p.Style().Options.PercentFormat = "%4.1f%%"

	d.pgWriter = p

	go d.pgWriter.Render()

	d.pgTracker = &progress.Tracker{Message: filename, Total: total, Units: progress.UnitsDefault}

	d.pgWriter.AppendTracker(d.pgTracker)

	time.Sleep(time.Second * 1)
}

func (d *DownloadCommand) downloadProgress(num, written, total int64) {
	if d.pgTracker.IsDone() {
		return
	}

	if d.pgTracker.Value() >= total {
		d.pgTracker.MarkAsDone()
		return
	}
	d.pgTracker.Increment(num)
}

func (d *DownloadCommand) downloadFinish(written, total int64, err error) {
	time.Sleep(time.Millisecond * 200)
	if err == nil {
		log.Info("download success")
		return
	}
	if d.pgTracker != nil {
		d.pgTracker.MarkAsErrored()
	}
}

func (d *DownloadCommand) parseOption(opts []*Option) bool {
	for _, opt := range opts {
		switch opt.Name {
		case "docid":
			d.docId = opt.StrValue
		case "save":
			d.savedDir = opt.StrValue
		}
	}
	if d.docId == "" {
		log.Error("doc gns is invalid")
		return false
	}
	if d.savedDir == "" {
		log.Error("save dir is invalid")
		return false
	}
	return true
}

func (d *DownloadCommand) Arguments() []Argument {
	return nil
}

func (d *DownloadCommand) Options() []*Option {
	return []*Option{
		{
			ShortName:    "d",
			Name:         "docid",
			Description:  "download doc gns",
			OptType:      StrOption,
			DefaultValue: "",
		},
		{
			ShortName:    "s",
			Name:         "save",
			Description:  "save doc local dir",
			OptType:      StrOption,
			DefaultValue: "",
		},
	}
}

func (d *DownloadCommand) Description() string {
	return "Download doc to local dir"
}

func NewDownloadCommand() *DownloadCommand {
	return &DownloadCommand{}
}
